package com.controller;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.entity.Friend;
import com.entity.OnlineUser;

@ServerEndpoint("/websocket")
@Component
public class MyWebSocket {

	private static Logger log = LoggerFactory.getLogger(MyWebSocket.class);

	// key为用户名
	private static ConcurrentHashMap<String, MyWebSocket> onLineSocket = new ConcurrentHashMap<>();

	private Session session;

	private OnlineUser onlineUser;

	@OnOpen
	public void onOpen(Session session) {
		this.session = session;
		log.debug("有一个用户连接上");
	}

	@OnClose
	public void onClose() {
		onLineSocket.remove(this.onlineUser.getUser().getName());
		log.debug("有一个用户断开连接");
	}

	@OnMessage
	public void onMessage(String message, Session session) throws IOException {
		log.debug("来自客户端的消息:" + message);
		sendMessage(new JSONObject(message));
	}

	/**
	 * 发送消息
	 * 
	 * @param message
	 * @return
	 * @throws IOException
	 */
	public void sendMessage(JSONObject message) throws IOException {
		if (!validation(message)) {
			return;
		}
		// 消息
		if (2 == message.getInt("msgType")) {
			handleTextMsg(message);
		}
		// 登录
		if (0 == message.getInt("msgType")) {
			handleLogonInMsg(message);
		}
		// 退出
		if (1 == message.getInt("msgType")) {
			handleLogonOutMsg(message);
		}

	}

	/**
	 * 处理退出的消息
	 * 
	 * @param message
	 * @throws IOException
	 */
	private void handleLogonOutMsg(JSONObject message) throws IOException {
		// 通知所有的好友
		sendMsgToAllFriend(message, onlineUser);
		// 将登陆的用户放入onLineSocket
		message.put("errorCode", 0);
		this.session.getBasicRemote().sendText(message.toString());
		MyWebSocket.onLineSocket.remove(this.onlineUser.getUser().getName());
		this.session.close();
	}

	/**
	 * 处理登陆消息
	 * 
	 * @param message
	 * @throws IOException
	 */
	private void handleLogonInMsg(JSONObject message) throws IOException {
		// 获得消息中的令牌
		String token = message.getString("token");
		// 根据令牌获得刚刚登陆的用户
		this.onlineUser = WebController.onlineUserMap.get(token);
		// 取出之后移除
		WebController.onlineUserMap.remove(token);
		// 通知所有的好友
		sendMsgToAllFriend(message, onlineUser);
		// 将登陆的用户放入onLineSocket
		MyWebSocket.onLineSocket.put(onlineUser.getUser().getName(), this);
		message.put("errorCode", 0);
		this.session.getBasicRemote().sendText(message.toString());
	}

	/**
	 * 发送消息到所有的好友
	 * 
	 * @param message
	 * @throws IOException
	 */
	private void sendMsgToAllFriend(JSONObject message, OnlineUser onlineUser) throws IOException {
		if (onlineUser != null) {
			message.put("errorCode", 1);
			for (Friend friend : onlineUser.getFriends()) {
				MyWebSocket onlineUserFriend = MyWebSocket.onLineSocket.get(friend.getFriendName());
				if (onlineUserFriend != null && onlineUserFriend.getSession().isOpen()) {
					onlineUserFriend.getSession().getBasicRemote().sendText(message.toString());
				}
			}
		}
	}

	/**
	 * 处理用户的正常发送text消息的方法
	 * 
	 * @param message
	 * @throws IOException
	 */
	private void handleTextMsg(JSONObject message) throws IOException {
		// 消息的接收者
		MyWebSocket onLineRecever = onLineSocket.get(message.getString("receiver"));
		message.put("errorCode", 1);
		// 消息发送给接收者
		onLineRecever.getSession().getBasicRemote().sendText(message.toString());
		message.put("errorCode", 0);
		// 消息在发送给自己
		this.session.getBasicRemote().sendText(message.toString());
	}

	/**
	 * 校验消息的正确性
	 * 
	 * @param message
	 * @return
	 * @throws IOException
	 */
	private boolean validation(JSONObject message) throws IOException {
		// 登录不用校验
		if (message.getInt("msgType") == 0) {
			return true;
		}

		// 消息的发送者是否就是本方法的接收者
		if (!this.onlineUser.getUser().getName().equals(message.getString("sender"))) {
			message.put("errorCode", -5);
			// 消息在发送给自己
			this.session.getBasicRemote().sendText(message.toString());
			return false;
		}
		// 校验令牌
		String token = message.getString("token");
		if (!this.onlineUser.getToken().equals(token)) {
			message.put("errorCode", -2);
			// 消息在发送给自己
			this.session.getBasicRemote().sendText(message.toString());
			return false;
		}

		// 发送消息校验
		if (message.getInt("msgType") == 2) {
			// 校验是否是初次连接
			if (this.onlineUser == null) {
				message.put("errorCode", -4);
				// 消息在发送给自己
				this.session.getBasicRemote().sendText(message.toString());
				return false;
			}
			// 校验接受者是否是好友
			if (!isUFriend(message.getString("receiver"))) {
				message.put("errorCode", -3);
				// 消息在发送给自己
				this.session.getBasicRemote().sendText(message.toString());
				return false;
			}
			// 校验接收者在线否
			MyWebSocket onLineRecever = onLineSocket.get(message.getString("receiver"));
			if (onLineRecever == null || onLineRecever.getSession() == null || onLineRecever.getSession().isOpen()) {
				message.put("errorCode", -1);
				// 消息在发送给自己
				this.session.getBasicRemote().sendText(message.toString());
				return false;
			}
		}
		// 退出
		if (message.getInt("msgType") == 1) {

		}
		return true;
	}

	/**
	 * 判断传入的好有名称是否真的是你的好友
	 * 
	 * @param friendName
	 * @return
	 */
	private boolean isUFriend(String friendName) {
		Set<Friend> friends = onlineUser.getFriends();
		for (Friend friend : friends) {
			if (friend.getFriendName().equals(friendName)) {
				return true;
			}
		}
		return false;
	}

	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}

	public OnlineUser getOnlineUser() {
		return onlineUser;
	}

	public void setOnlineUser(OnlineUser onlineUser) {
		this.onlineUser = onlineUser;
	}

}